home *** CD-ROM | disk | FTP | other *** search
- Subject: v14i056: VN NNTP conversion kit
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Bob Mcqueer <rtech!bobm>
- Posting-number: Volume 14, Issue 56
- Archive-name: vn.nntp.pch
-
- [ VN is a newsreader for netnews. The latest version appeared here a
- few months ago. This distribution allows VN to work with NNTP.
- There's also a hack to feed from different servers. --r$ ]
-
-
- This contains replacements for 3 files:
-
- std.c config_std.h and Makefile.
-
- I'm not doing it as patches because the context diffs for std.c would be
- much larger than the file in the first place, and the other 2 are small.
-
- This source also allows building of a non-NNTP version, and any future
- patches on std.c, etc. should be against these sources.
-
- Read new file nntp.doc for details.
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # nntp.doc
- # Makefile
- # config_std.h
- # std.c
- export PATH; PATH=/bin:$PATH
- echo shar: extracting "'nntp.doc'" '(3844 characters)'
- if test -f 'nntp.doc'
- then
- echo shar: will not over-write existing file "'nntp.doc'"
- else
- cat << \SHAR_EOF > 'nntp.doc'
- Notes concerning NNTP changes:
-
- The NNTP changes only effect the vns_* routines, which are all defined
- in std.c. Rather than provide a different set, std.c was ifdef'ed for
- NNTP, since a significant amount of code is shared with the non-NNTP
- version.
-
- Affected files: std.c config_std.h Makefile
-
- The response_codes.h header file from NNTP distribution is needed, and
- the server_init(), get_server(), put_server() and close_server()
- routines (clientlib.o).
-
- The NNTP changes reflect something done at rtech - we have multiple
- news installations going on different machines. Basically, local
- newsgroups were setup on a different machine than our USENET gateway,
- and one has to talk to the rtech newsserver to get USENET, or one of
- 2 other machines to get different sets of local newsgroups. The way
- the support folks here set up rrn appears to have been to make
- differently configured executables, then cover with a shell script
- that invokes the right one for the machine you wanted to go to. You
- wind up with a separate .newsrc for each machine, using a local naming
- convention.
-
- I wanted to make vn able to handle this in one executable, so I
- introduced some command line flags aimed at specifying .newsrc file
- and machine to talk to. All of these flags begin with "+", distinguishing
- them from the normal options. The "+" flags are exclusively
- command line, and can not be set in the .newsrc:
-
- +n <file> specify .newsrc file. If not beginning with /,
- taken with respect to HOME. If this isn't
- specified, the normal NEWSRC variable / default
- logic applies.
-
- +m <machine> specify machine to talk to. There will be a site-
- determined default if this isn't specified, which may
- be overridden by setting a VNMACHINE variable.
-
- +l rather than using NNTP, read the news locally.
-
- +t <file> trace the NNTP server session in <file> for debugging.
-
- If compiled for non-NNTP, only the '+n' flag applies. Given these flags,
- people can invoke vn as they see fit, set aliases for how they want to talk
- to different machines, etc.
-
- The machine name enters into interaction with the NNTP server only as the
- argument to server_init().
-
- The people setting up rrn here also made different inews executables for
- posting to installations on different machines, again with a local naming
- convention. To handle this, the posting command may have a %s embedded
- in it, which will get substituted with the machine name before being
- spawned. This way, it can either be a command flag, or a path to an
- alternate executable, as in our case. User POSTER variables will also
- have to be aware of that fact, if appropriate.
-
- Also note the KEEP_UNK definition in .newsrc - another hack for this
- multiple installation stuff.
-
- Differences between the distributed config_std.h, and what is run here,
- apart from DEF_MACHINE, of course:
-
- DEF_POSTER points to a non-standard location for inews, with a %s
- in it for machine name substitution.
-
- SHOW_FROM is defined.
-
- KEEP_UNK is defined.
-
- What I compile for a non-NNTP version (it runs that way on the rtech
- gateway (ULTRIX), which is hardly anybody's "home" machine) is completely
- standard.
-
- Our local NNTP versions are running on Pyramid, CCI and Sun. It has also
- been built on a Convergent Technologies machine, but NNTP seems to have
- some problems in that environment - after communicating to the server for
- a while you get a "broken pipe". Since it affects rrn on that machine
- also, it's obviously not vn's problem. It's just that rrn at least gets
- part way through a session before dying, and vn invariably dies while
- trying to read article headers at start up. And it's only talking to
- the ULTRIX microvax, not talking to the CCI machine which is where our
- local newsgroups live. If NFS or NNTP guru out there has any bright
- ideas I'll pass them on to the guy who's looking at this.
- SHAR_EOF
- fi # end of overwriting check
- echo shar: extracting "'Makefile'" '(3869 characters)'
- if test -f 'Makefile'
- then
- echo shar: will not over-write existing file "'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- # CFLAGS:
- # set -DJOBCONTROL if you have job control (BSD).
- # set -DSYSV -Dindex=strchr -Drindex=strrchr on Sytem V systems
- # set -Dregfree=free if you DON'T include reg.o (SYSV + some BSD)
- #
- # JOBCONTROL could be done as #ifndef SYSV, I suppose, but this clearly
- # marks that particular difference.
- #
- # LIBS:
- # should point to any extra libraries needed, such as termcap. You
- # may want to change this to use the curses termcap cover. If you need
- # to pull in another library to get regex / regcmp or strtok on non-SYSV
- # systems, you may want to put that here. I understand that -lPW is now
- # required on many SYSV systems to pick up regex/regcmp, hence that is
- # reflected here.
- #
- # EXTRAOBJS:
- # may be used to include tmpnam.o, strtok.o, reg.o in the list.
- #
- # These objects implement SYSV utilities for BSD machines.
- #
- # strtok.o implements strtok() / strpbrk(). reg.o implements regex()/regcmp()
- # on top of the BSD regular expression library (regex() allows multiple
- # regular expressions). tmpnam.o implements tmpnam() of course.
- #
- # If you have them, use your own regex/regcmp, because:
- #
- # i) They should be faster than the reg.c code, which
- # recompiles the "current" ucb string every time you
- # switch regular expressions.
- #
- # ii) I'm using reg.c myself on a couple systems, and it seems to
- # work. But implementing one set of system calls on top of a
- # different set is always a bit suspect, and why add code when
- # you don't need to.
- #
- # if you DON'T include reg.o, be sure you set -Dregfree=free in CFLAGS.
- #
- # As with regex, if you have a system strtok(), it is likely more efficient -
- # string routines will often be done in assembler on a given machine.
- #
- # Even if you have it, you can use tmpnam.o anyhow. This version will tailor
- # the temp file name to vnXXXXXX, instead of a generic tmpXXXXXX.
- #
- # "vanilla" BSD. This has been used locally on Pyramids / CCI / Sun.
- #LIBS = -ltermcap
- #EXTRAOBJS = tmpnam.o strtok.o reg.o
- #CFLAGS = -O -DJOBCONTROL
- #
- # "vanilla" SYSV:
- #LIBS = -ltermcap -lPW
- #EXTRAOBJS = tmpnam.o
- #CFLAGS = -O -DSYSV -Dregfree=free -Dindex=strchr -Drindex=strrchr
- #
- # BSD with strtok() / regex(), such as ULTRIX. These are the rules
- # used for our non-NNTP installation (rtech is a microvax running ULTRIX):
- #LIBS = -ltermcap
- #EXTRAOBJS = tmpnam.o
- #CFLAGS = -O -DJOBCONTROL -Dregfree=free
-
- # SERVEROBJS defines the object(s) for the vns_xxxx "server" interface.
- #
- # std.o is the version for "standard" news, making use of the
- # users .newsrc file, and resident articles / active file.
- # If you compile std.c with NNTP defined you get the version
- # of vn which will talk to an NNTP server. You will also have
- # to define where to pick up the response_codes.h header file,
- # and where the server library is (server_init, etc.). It is also
- # 99.9% certain that you will want to change DEF_MACHINE in
- # config_std.h. For this reason, config_std.h has the definition
- # commented out, which will cause a syntax error until you fix it.
- # See the special NNTP version rule for std.o following the vn rule
- #
- SERVEROBJS = std.o
- SERVERLIBS =
-
- # normal vn objects
- #
- VNOBJS= hash.o envir_set.o pagefile.o reader.o storage.o sig_set.o term_set.o tty_set.o userlist.o vn.o vnglob.o digest.o strings.o session.o printex.o getch.o help.o newdisp.o stat.o svart.o
-
- # This is to force you to read the makefile. Once you have, comment this rule,
- # and uncomment the "real" rule. At the minimum, you will also have to
- # uncomment one of the three sets of LIBS / EXTRAOBJS & CFLAGS definitions
- # above. For the NNTP version you will also have to uncomment and modify
- # the std.o special rule, and pick up server_init, etc. from somewhere.
- #
- vn:
- @echo "PLEASE READ THE MAKEFILE"
- #vn: $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS)
- # cc -o vn $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS) $(SERVERLIBS) $(LIBS)
- #
- #std.o :
- # cc -c $(CFLAGS) -DNNTP -I. std.c
- SHAR_EOF
- fi # end of overwriting check
- echo shar: extracting "'config_std.h'" '(5941 characters)'
- if test -f 'config_std.h'
- then
- echo shar: will not over-write existing file "'config_std.h'"
- else
- cat << \SHAR_EOF > 'config_std.h'
- /*
- ** default news poster
- ** If talking to an NNTP server, and there is a %s in this somewhere,
- ** the machine will be substituted at runtime
- **
- ** LOC_POST only applies for NNTP. It is the poster used in conjunction
- ** with the +l option or NULL for DEF_MACHINE, ie. when you are reading
- ** the local files directly instead of through NNTP.
- */
- #define DEF_POST "/usr/lib/news/inews -h"
- #define LOC_POST "/usr/lib/news/inews -h"
-
- /*
- ** DEF_MACHINE
- **
- ** this will affect only NNTP versions, and will have to differ from
- ** site to site. shipped commented out so that you will be forced to set it
- **
- ** NULL or empty string will result in direct reading of the local files
- ** rather than NNTP.
- #define DEF_MACHINE "rtech"
- */
-
- /*
- ** SHOW_FROM applies only to NNTP. If defined, a FROM line will be
- ** placed in the user's file when posting followups. FROM_CR_FORM
- ** is the format used for the From line, with arguments corresponding
- ** to the "From: " header, the user name, the machine name and the user's
- ** "gecos" string, in that order.
- **
- ** This is distributed turned off, since the feature may encourage
- ** userid forgery. If turned off, vn will prepend the user's article
- ** with the FROM line instead, effectively preventing the user from
- ** specifying one. In the non-NNTP case, inews runs as the user,
- ** and constructs a FROM line if the user didn't
- **
- ** If SHOW_FROM is not defined, REPLY_CR_FORM may be defined, which shows
- ** the user a "Reply-to" line to edit into a more appropriate mail reply path.
- ** If defined, REPLY_CR_FORM is the format used for the line with arguments
- ** corresponding to the "Reply-to: " header, the user name, and the machine
- ** name, in that order.
- **
- ** An important point is that since the _FORM strings have the header as one
- ** of their arguments, they had better begin with "%s" to work right.
- **
- ** The machine placed into these lines is the HOST machine, usually.
- ** If FROM_REAL is defined, the actual machine the user is logged into
- ** is used instead. Using the host works well locally, since our news
- ** gateway also functions as a mail gateway. If you ALSO define MACH_CONCAT,
- ** the machine placed into the from line will be <host>!<real>. Using
- ** either of these alternatives may lead to problems since you are then
- ** displaying your internal machine names to the outside world, and the
- ** names are very likely conflict with some net site or another.
- #define FROM_REAL
- #define MACH_CONCAT
- #define SHOW_FROM
- #define REPLY_CR_FORM "%s%s@%s.UUCP"
- */
- #define FROM_CR_FORM "%s%s@%s.UUCP (%s)"
-
- /*
- ** default user .newsrc file
- */
- #define DEF_NEWSRC ".newsrc"
-
- /*
- ** If INLETTER is defined, the address line will be placed into the
- ** file editted by the user, and the mailer is assumed smart enough
- ** to understand about header lines in the file. Otherwise the
- ** address is part of the mailer's command line.
- **
- ** if MAILSMART is defined, The From: line will be used for mail replies,
- ** or overridden by a "Reply-to:" line if present - "Path:" will be used
- ** as a last resort. If MAILSMART is not defined, "Path:" will simply be
- ** used.
- **
- ** if MAILCHOOSE is defined, the user is prompted before edit with all
- ** of the address lines to choose from, or to input a new one. MAILCHOOSE
- ** makes MAILSMART irrelevant, but the two are independent of INLETTER.
- **
- #define MAILCHOOSE
- */
- #define MAILSMART
- #define INLETTER
-
- /*
- ** default mail sender. If INLETTER, will be done as
- ** cat <file> | DEF_MAIL, Otherwise, cat <file> | DEF_MAIL <address>
- ** user's MAILER variable will have to conform, too.
- */
- #ifdef INLETTER
- #define DEF_MAIL "/usr/lib/sendmail -t"
- #else
- #define DEF_MAIL "/bin/mail"
- #endif
-
- /*
- ** OLDRC defined for an apparently earlier news version which took unnamed
- ** command line options as synonyms for -n, and did not take ranges in
- ** the .newsrc file. Probably useless, but kept in for historical reasons.
- **
- **#define OLDRC
- */
-
- /*
- ** article spool directory
- */
- #define SPOOLDIR "/usr/spool/news"
-
- /*
- ** active file
- */
- #define ACTFILE "/usr/lib/news/active"
-
- /*
- ** maximum number of option lines in .newsrc
- */
- #define OPTLINES 60
-
- /*
- ** maximum number of filter options
- */
- #define NUMFILTER 30
-
- /*
- ** maximum number of file lines to search looking for header lines.
- */
- #define HDR_LINES 36
-
- /*
- ** When a newsgroup is scanned, we ignore articles less than <high spool> -
- ** MAXARTRANGE. This is intended to prevent ridiculous numbers of article
- ** opening attempts the first time a user reads a new newsgroup which has a
- ** huge difference between the high and low spool numbers, perhaps due to
- ** some articles not getting expired.
- */
- #define MAXARTRANGE 1600 /* about 2 weeks of soc.singles */
-
- /*
- ** If we detect that the user has a higher number in .newsrc than the
- ** high article number, obviously the active file is out of synch with the
- ** .newsrc. We set the user's number back to the low article number in
- ** this case, on the theory that it's better to repeat stuff than miss
- ** articles. On such setbacks, we won't backdate the user by more than
- ** SYN_SETBACK articles, preventing floods of articles on large newsgroups
- ** if you don't define SYN_CHECK, the user's number won't be adjusted in
- ** this case, choosing to lose articles rather than show old ones.
- */
- #define SYN_CHECK
- #define SYN_SETBACK 60
-
- /*
- ** Normally, unrecognized newsgroup names are silently removed from the
- ** user's .newsrc
- **
- ** if KEEP_UNK is defined, unknown newsgroups will be left alone in
- ** the users .newsrc. This is intended to allow the same .newsrc
- ** to be used against servers on different NNTP installations. Of course,
- ** it works only if newsgroup names are unique across installations.
- ** Essentially, this is a hack for our local situation, which may come
- ** in handy for somebody else. If this is defined, users will have to
- ** edit out bogus newsgroup names in their own .newsrc's if they wish
- ** to keep it accurate.
- #define KEEP_UNK
- */
- SHAR_EOF
- fi # end of overwriting check
- echo shar: extracting "'std.c'" '(31821 characters)'
- if test -f 'std.c'
- then
- echo shar: will not over-write existing file "'std.c'"
- else
- cat << \SHAR_EOF > 'std.c'
- #include <stdio.h>
- #include <pwd.h>
- #include <ctype.h>
- #include <sys/param.h>
- #ifdef NNTP
- #include <response_codes.h>
- #endif
- #include "server.h"
- #include "config_std.h"
- #include "std.h"
-
- #ifndef MAXPATHLEN
- #define MAXPATHLEN 240
- #endif
-
- extern NODE *hashfind();
- extern FILE *fopen();
- extern char *index(), *rindex();
- extern char *malloc();
- extern char *str_tstore(), *str_tpool(), *str_store();
- extern char *strtok(), *strpbrk();
- extern char *regex(), *regcmp();
-
- #ifdef MAILCHOOSE
- extern int (*Massage)();
- #endif
-
- /*
- global flags signifying options set
- */
- #define GF_ALL 1 /* -x option - scan everything */
- #define GF_SPEC 2 /* -n option(s) - user specified groups */
- #define GF_OVER 4 /* command line specification - overide marks */
-
- #ifdef NNTP
- char *nntp_get();
- static char *Machine;
- static char *Fmach;
- char *Vns_version = "nntp1.2";
- static FILE *Fp_trace = NULL;
- extern int (*Postfunc)();
- static int Server_open = 0;
- #else
- char *Vns_version = "res1.2";
- #endif
-
- static char *Home;
- static char *Username, *Userdesc;
- static char *Onews, *Newsrc;
- static int Ntopt, Nntopt, Nwopt, Nnwopt;
-
- static char *Wopt[NUMFILTER]; /* regular expressions for -w options */
- static char *Topt[NUMFILTER]; /* for -t options */
- static char *Negwopt[NUMFILTER]; /* for negated -w options */
- static char *Negtopt[NUMFILTER]; /* for negated -t options */
-
- static char *Options[OPTLINES];
- static int Max_name, Optlines;
- static unsigned Gflags = 0;
- static char **Active;
- static int Actnum;
- static char *Mailer, *Poster;
-
- static char *RT_head = RTHEAD;
- static char *P_head = PHEAD;
- static char *M_head = MHEAD;
- static char *R_head = RHEAD;
- static char *TO_head = TOHEAD;
- static char *F_head = FHEAD;
- static char *FT_head = FTHEAD;
- static char *T_head = THEAD;
- static char *DIS_head = DISHEAD;
- static char *L_head = LHEAD;
- static char *N_head = NHEAD;
-
- static char *Fpfix = FPFIX;
-
- /*
- ** environment setup.
- */
- vns_envir()
- {
- char dbuf[MAXPATHLEN], *rcname;
- char *vn_env();
- struct passwd *ptr, *getpwuid();
- char *machine;
- #ifdef NNTP
- #ifndef SHOW_FROM
- int nntp_post();
- #endif
- #endif
- #ifdef MAILCHOOSE
- int mail_prompt();
-
- Massage = mail_prompt;
- #endif
-
- ptr = getpwuid (getuid());
- Home = str_store(ptr->pw_dir);
- Username = str_store(ptr->pw_name);
- Userdesc = str_store(ptr->pw_gecos);
-
- #ifdef NNTP
- Machine = vn_env("VNMACHINE",DEF_MACHINE);
- #ifndef SHOW_FROM
- Postfunc = nntp_post;
- #endif
- #endif
-
- rcname = vn_env("MAILER",DEF_MAIL);
- #ifdef INLETTER
- sprintf(dbuf,"cat %%s | %s",rcname);
- #else
- /* used as a format string TWICE (%%%% -> %% -> %) */
- sprintf(dbuf,"cat %%%%s | %s %%s",rcname);
- #endif
- Mailer = str_store(dbuf);
-
- rcname = vn_env("NEWSRC",DEF_NEWSRC);
- if (*rcname != '/')
- {
- sprintf (dbuf, "%s/%s",Home,rcname);
- Newsrc = str_store (dbuf);
- }
- else
- Newsrc = str_store (rcname);
- }
-
- /*
- change directory to group
- */
- vns_gset(grp)
- char *grp;
- {
- char dbuf [RECLEN];
-
- #ifdef NNTP
- if (Machine != NULL)
- {
- sprintf(dbuf,"group %s",grp);
- if (nntp_put(dbuf,dbuf) < 0)
- printex("can't find newsgroup (server: %s)",dbuf);
- return;
- }
- #endif
- g_dir (grp,dbuf);
- if (chdir(dbuf) < 0)
- printex("can't change to newsgroup directory");
- }
-
- /*
- g_dir converts newsgroup name to directory string
- */
- static
- g_dir(s,t)
- char *s,*t;
- {
- char *ptr;
- sprintf (t,"%s/%s",SPOOLDIR,s);
- for (ptr=t+strlen(SPOOLDIR)+1; (ptr = index(ptr,'.')) != NULL; *ptr = '/')
- ;
- }
-
- /*
- ** myfind is used for hashfind() calls which aren't supposed to fail.
- */
- static NODE *
- myfind(name)
- char *name;
- {
- NODE *n;
-
- n = hashfind(name);
- if (n == NULL)
- printex("Unexpected table lookup failure");
- return (n);
- }
-
- vns_news(argc,argv,lfirst,nun)
- int argc;
- char **argv;
- int *lfirst, *nun;
- {
- FILE *fp;
- static char marks[] =
- {
- NEWS_ON, NEWS_OFF, '\0'
- };
- int line, len, num;
- char buf [RECLEN], trail, submark, *fret, *ptr;
- int optpflag;
-
- ++argv;
- --argc;
-
- /*
- ** get .newsrc / server connection affecting options before
- ** calling fill_active.
- */
- arg_opt(argc,argv);
-
- /*
- ** fill table with active newsgroups - initiates server connection
- ** if we're talking to NNTP.
- */
- fill_active ();
-
- /*
- ** handle options, now that fill_active has been called.
- ** Set GF_OVER before calling newsrc_opt, since -S may override it.
- */
- if (Optlines > 0)
- {
- optpflag = 1;
- Gflags |= GF_OVER;
- newsrc_opt(lfirst,nun);
- }
- else
- optpflag = 0;
-
- if ((fp = fopen (Newsrc,"r")) == NULL)
- printex ("can't open %s for reading",Newsrc);
-
- Optlines = 0;
-
- for (line = 1; (fret = fgets(buf,RECLEN-1,fp)) != NULL && emptyline(buf) == 1; ++line)
- ;
- if (fret != NULL && strncmp (buf,"options",7) == 0)
- {
- Options[0] = str_store(buf);
- Optlines = 1;
- trail = buf [strlen(buf)-2];
- for ( ; (fret = fgets(buf,RECLEN-1,fp)) != NULL; ++line)
- {
- if (trail != '\\' && buf[0] != ' ' && buf[0] != '\t')
- break;
- if (Optlines >= OPTLINES)
- printex ("%s - too many option lines (%d allowed)",Newsrc,OPTLINES);
- Options[Optlines] = str_store(buf);
- ++Optlines;
- if ((len = strlen(buf)) >= 2 && buf[len-2] != '\\')
- trail = buf[len-2];
- else
- trail = '\0';
- }
- }
-
- /* do the options from the newsrc file if there weren't command line args */
- if (Optlines > 0 && ! optpflag )
- newsrc_opt (lfirst,nun);
-
- for ( ; fret != NULL; ++line, fret = fgets(buf,RECLEN-1,fp))
- {
- if (emptyline(buf) == 1)
- continue;
- if ((ptr = strpbrk(buf,marks)) == NULL)
- {
- fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
- line,Newsrc,buf);
- continue;
- }
- submark = *ptr;
- *ptr = '\0';
- ++ptr;
- num = 0;
- for (ptr = strtok(ptr," ,-\n"); ptr != NULL; ptr = strtok(NULL," ,-\n"))
- {
- len = atoi (ptr);
- for ( ; *ptr >= '0' && *ptr <= '9'; ++ptr)
- ;
- if (*ptr != '\0' || len < num)
- {
- num = -1;
- fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
- line,Newsrc,buf);
- break;
- }
- num = len;
- }
- if (num < 0)
- continue;
- chkgroup (buf,submark,num,0);
- }
- fclose (fp);
-
- /* now take care of groups not specified in .newsrc */
- art_active();
-
- /* free up the option string storage */
- for (num=0; num < Ntopt; ++num)
- regfree (Topt[num]);
- for (num=0; num < Nwopt; ++num)
- regfree (Wopt[num]);
- for (num=0; num < Nntopt; ++num)
- regfree (Negtopt[num]);
- for (num=0; num < Nnwopt; ++num)
- regfree (Negwopt[num]);
- Ntopt = Nwopt = Nntopt = Nnwopt = 0;
-
- /* free the active list */
- free ((char *) Active);
- }
-
- static
- emptyline(s)
- char *s;
- {
- while (isspace(*s))
- ++s;
- if (*s == '\0')
- return (1);
- return (0);
- }
-
- /*
- fill hash table from active news group list
- This is needed to be able to process options
- before scanning user order. Constructs an array
- of active newsgroup names for the rest of vns_nws().
- */
- static
- fill_active ()
- {
- FILE *f;
- char *nread, act_rec[RECLEN];
- int num,lownum,rcount;
- char *(*getfn)();
-
- Max_name = 0;
-
- #ifdef NNTP
- if (Machine != NULL)
- {
- if (server_init(Machine) < 0)
- {
- printex ("Cannot connect to NNTP server on %s",Machine);
- }
- Server_open = 1;
- getfn = nntp_get;
- if (nntp_put("list",act_rec) < 0)
- printex ("Couldn't get newsgroup list (server: %s)",act_rec);
- }
- else
- {
- getfn = fgets;
- if ((f = fopen (ACTFILE,"r")) == NULL)
- printex ("couldn't open %s\n",ACTFILE);
- }
- #else
- getfn = fgets;
- if ((f = fopen (ACTFILE,"r")) == NULL)
- printex ("couldn't open %s\n",ACTFILE);
- #endif
-
- /*
- ** we do things this way so that we only examine active records
- ** once, minimizing the window where changes could screw us up
- ** at the cost of possibly alloc'ing a few extra bytes. We start
- ** with a count of one to have a positive rcount for alloc.
- */
- for(rcount=1; (*getfn)(act_rec, RECLEN-1, f) != NULL; ++rcount)
- ;
- if ((Active = (char **) malloc(rcount*sizeof(char *))) == NULL)
- printex("Memory allocation failure");
-
- #ifdef NNTP
- if (Machine != NULL)
- {
- if (nntp_put("list",act_rec) < 0)
- printex ("Couldn't re-get newsgroup list (server: %s)",act_rec);
- }
- else
- rewind(f);
- #else
- rewind(f);
- #endif
-
- Actnum = 0;
- while (Actnum < rcount && (*getfn)(act_rec, RECLEN-1, f) != NULL)
- {
- if (strtok (act_rec," \n") == NULL)
- continue;
- nread = strtok (NULL, " \n");
- if (nread != NULL)
- num = atoi(nread);
- else
- num = 0;
- nread = strtok (NULL, " \n");
- if (nread != NULL)
- lownum = atoi(nread);
- else
- lownum = 0;
- if (lownum > 0)
- --lownum;
- if (strlen(act_rec) > Max_name)
- Max_name = strlen(act_rec);
-
- /* enter newsgroup, point to permanent copy of name */
- hashenter (act_rec, num, lownum);
- Active[Actnum] = (myfind(act_rec))->nd_name;
- ++Actnum;
- }
-
- #ifdef NNTP
- if (Machine == NULL)
- fclose (f);
- #else
- fclose (f);
- #endif
- }
-
- /*
- check active newsgroups not mentioned in NEWSRC file
- (SFLG_SCAN not set)
- */
- static
- art_active ()
- {
- int i;
- NODE *ptr;
-
- for( i=0; i < Actnum; ++i)
- {
- ptr = myfind(Active[i]);
- if ((ptr->state & SFLG_SCAN) == 0)
- chkgroup (ptr->nd_name, NEWS_ON, 0, 1);
- }
- }
-
- /*
- check group for new articles:
- s - group
- c - subscription indicator from NEWSRC
- n - number read
- new - new newsgroup flag
- */
- static
- chkgroup (s,c,n,new)
- char *s,c;
- int n;
- int new;
- {
- NODE *ptr;
- char sub;
- int nrd;
- int lowart;
- int st;
-
- if ((ptr = hashfind(s)) != NULL && (ptr->state & SFLG_SCAN) == 0)
- {
- ptr->state |= SFLG_SCAN;
-
- #ifdef SYN_CHECK
- /* if "read" more than exist, reset */
- if (n > ptr->highnum)
- {
- n = ptr->highnum - SYN_SETBACK;
- fgprintf("%s: .newsrc out of synch, resetting\n",s);
- }
- #endif
- lowart = ptr->lownum;
- if (n < ptr->lownum)
- n = ptr->lownum;
-
- nrd = n;
- sub = c;
-
- /*
- ** scan decision is rather complex, since GF_ALL setting
- ** overides "n" value, GF_SPEC indicates SFLG_SPEC flag used.
- ** if GF_OVER set, SFLG_SPEC overides subscription mark, else
- ** SFLG_SPEC AND subscribed is neccesary.
- */
- if ((Gflags & GF_SPEC) != 0)
- {
- if ((ptr->state & SFLG_SPEC) == 0)
- c = NEWS_OFF;
- else
- {
- if ((Gflags & GF_OVER) != 0)
- c = NEWS_ON;
- }
- }
- if ((Gflags & GF_ALL) != 0)
- n = lowart;
- fw_group(s, new, sub == NEWS_ON, nrd, c == NEWS_ON);
- if (c == NEWS_ON && ptr->highnum > n)
- {
- st = outgroup (s,n,ptr->highnum);
- if (st > nrd)
- fw_chg(new, sub == NEWS_ON, st, c == NEWS_ON);
- }
- }
- #ifdef KEEP_UNK
- else
- {
- /*
- ** enter unknown group into the list with no articles and
- ** no scanning for statistics. Simply a device so we'll
- ** write it back out again after we're done.
- */
- if (ptr == NULL)
- {
- hashenter (s, n, n);
- fw_group(s, 0, c == NEWS_ON, n, 0);
- }
- }
- #endif
- }
-
- /*
- vns_write writes the .newsrc file
- */
- vns_write(news,ncount)
- NODE **news;
- int ncount;
- {
- FILE *fp;
- NODE *p;
- char c;
- int i,rc;
-
- if (link(Newsrc,Onews) < 0)
- printex ("can't backup %s to %s before writing",Newsrc,Onews);
-
- if (unlink(Newsrc) < 0 || (fp = fopen(Newsrc,"w")) == NULL)
- printex ("can't open %s for writing (backed up in %s)",Newsrc,Onews);
- else
- {
- clearerr(fp);
- for (i=0; (rc = ferror(fp)) == 0 && i < Optlines; ++i)
- fprintf (fp,"%s",Options[i]);
- for (i=0; rc == 0 && i < ncount; ++i)
- {
- p = news[i];
- if ((p->flags & FLG_SUB) == 0)
- c = NEWS_OFF;
- else
- c = NEWS_ON;
- #ifdef OLDRC
- fprintf (fp,"%s%c %d\n",p->nd_name,c,p->rdnum);
- #else
- if (p->rdnum > 0)
- fprintf(fp,"%s%c 1-%d\n",p->nd_name,c,p->rdnum);
- else
- fprintf(fp,"%s%c 0\n",p->nd_name,c);
- #endif
- rc = ferror(fp);
- }
- fclose (fp);
- if (rc != 0)
- printex ("write of %s failed, old copy stored in %s",Newsrc,Onews);
- else
- unlink (Onews);
- }
- }
-
- /*
- arg_opt must be called prior to option scanning, since
- it uses the options array. This is a bit of a kludge,
- but it saves a bunch of work. NOTE - no command name argument
-
- This also processes the arguments which don't correspond to
- the .newsrc options - these arguments are all flagged with '+'
- */
- static
- arg_opt (argc,argv)
- int argc;
- char **argv;
- {
- int i;
- char bufr[RECLEN];
-
- Optlines = 0;
- for (i=0; i < argc; ++i,++argv)
- {
- if (**argv == '+')
- {
- ++(*argv);
- switch (**argv)
- {
- #ifdef NNTP
- case 't':
- ++(*argv);
- if (**argv == '\0')
- {
- ++argv;
- ++i;
- }
- Fp_trace = fopen(*argv,"w");
- break;
- case 'l':
- Machine = NULL;
- break;
- case 'm':
- ++(*argv);
- if (*(Machine = *argv) == '\0')
- {
- ++argv;
- ++i;
- Machine = *argv;
- }
- break;
- #endif
- case 'n':
- ++(*argv);
- if (*(Newsrc = *argv) == '\0')
- {
- ++argv;
- ++i;
- Newsrc = *argv;
- }
- if (*Newsrc != '/')
- {
- sprintf(bufr,"%s/%s",Home,Newsrc);
- Newsrc = str_store(bufr);
- }
- break;
- default:
- printex("unknown option, +%c",**argv);
- }
- continue;
- }
-
- if (Optlines >= OPTLINES)
- printex ("too many command line options (%d allowed)\n",
- OPTLINES);
- Options[Optlines] = *argv;
- ++Optlines;
- }
-
- /* now that we have machine name, resolve Poster command, Fmach */
- #ifdef NNTP
-
- /* make an empty machine synonomous with NULL */
- if (Machine != NULL && *Machine == '\0')
- Machine = NULL;
- if (Machine != NULL)
- {
- #ifdef FROM_REAL
- gethostname(bufr,RECLEN/2);
- Fmach = str_store(bufr);
- #ifdef MACH_CONCAT
- sprintf(bufr,"%s!%s",Machine,Fmach);
- Fmach = str_store(bufr);
- #endif
- #else
- Fmach = Machine;
- #endif
- Poster = vn_env("VNPOSTER",DEF_POST);
- sprintf(bufr,Poster,Machine);
- Poster = str_store(bufr);
- }
- else
- {
- Postfunc = NULL;
- Poster = vn_env("VNPOSTER",LOC_POST);
- }
- #else
- Poster = vn_env("VNPOSTER",DEF_POST);
- #endif /* NNTP */
- sprintf(bufr,"%s %%s",Poster);
- Poster = str_store(bufr);
-
- if (access (Newsrc,0) != 0)
- creat (Newsrc,0666);
-
- strcpy(bufr,Newsrc);
- strcpy(rindex(bufr,'/')+1,".vnXXXXXX");
- mktemp(bufr);
- Onews = str_store (bufr);
- }
-
- /*
- option setting routine:
- sets global flags: GF_ALL for -x option GF_SPEC for -n.
- sets up filter array for article scanning
- */
- static
- newsrc_opt(lfirst,nun)
- int *lfirst, *nun;
- {
- int i;
- char curopt,tmp[RECLEN],*tok;
-
- *nun = *lfirst = 0;
- Ntopt = Nwopt = Nnwopt = Nntopt = 0;
- curopt = '\0';
- for (i=0; i < Optlines; ++i)
- {
- strcpy(tmp,Options[i]);
- for (tok = strtok(tmp,",\\ \t\n"); tok != NULL; tok = strtok(NULL,",\\ \t\n"))
- {
- if (*tok != '-')
- do_opt (curopt,tok);
- else
- {
- for (++tok; index("nwt",*tok) == NULL; ++tok)
- {
- /* options with no strings */
- switch(*tok)
- {
- case 'S':
- Gflags &= ~GF_OVER;
- break;
- case '%':
- *lfirst = 1;
- break;
- case 'U':
- *nun = 1;
- break;
- #ifdef OLDRC
- case 'i':
- /* Treat "-i" as synonym for "-x" */
- #endif
- case 'x':
- Gflags |= GF_ALL;
- default:
- break;
- }
- }
- curopt = *tok;
- if (*(++tok) != '\0')
- do_opt (curopt,tok);
- }
- }
- }
- }
-
- /* do_opt is for options with strings attached */
- static
- do_opt (opt,str)
- char opt, *str;
- {
- switch (opt)
- {
- case 'n':
- Gflags |= GF_SPEC;
- specmark(str);
- break;
- case 'w':
- specfilter (FIL_AUTHOR,str);
- break;
- case 't':
- specfilter (FIL_TITLE,str);
- break;
- default:
- #ifdef OLDRC
- Gflags |= GF_SPEC; /* Assume anything else is newsgroup */
- specmark(str);
- #endif
- break;
- }
- }
-
- static
- specfilter (comp,str)
- char comp,*str;
- {
- int *count;
- char **rex;
-
- /*
- ** we may set rex one past end of array. we will error before
- ** referencing it if that's the case, however.
- */
- if (*str == '!')
- {
- if (comp == FIL_TITLE)
- {
- count = &Nntopt;
- rex = Negtopt + *count;
- }
- else
- {
- count = &Nnwopt;
- rex = Negwopt + *count;
- }
- ++str;
- }
- else
- {
- if (comp == FIL_TITLE)
- {
- count = &Ntopt;
- rex = Topt + *count;
- }
- else
- {
- count = &Nwopt;
- rex = Wopt + *count;
- }
- }
- if (*count >= NUMFILTER)
- printex ("too many %c options, %d allowed",comp,NUMFILTER);
- if ((*rex = regcmp(str,(char *) 0)) == NULL)
- printex ("%c option regular expression syntax: %s",comp,str);
- ++(*count);
- }
-
- /*
- handle the newsgroup specification string.
- ("all" convention - braack!!!)
- */
- static
- specmark (s)
- char *s;
- {
- unsigned ormask,andmask;
- int i,len;
- char *ptr,*re,pattern[RECLEN];
- NODE *nptr;
-
- if (*s == '!')
- {
- ++s;
- ormask = 0;
- andmask = ~SFLG_SPEC;
- if (*s == '\0')
- return;
- }
- else
- {
- ormask = SFLG_SPEC;
- andmask = 0xffff;
- }
-
- /* convert "all" not bounded by alphanumerics to ".*". ".all" becomes ".*" */
- for (ptr = s; (len = findall(ptr)) >= 0; ptr += len+1)
- {
- if (len > 0 && isalnum (ptr[len-1]))
- continue;
- if (isalnum (ptr[len+3]))
- continue;
- if (len > 0 && ptr[len-1] == '.')
- {
- --len;
- strcpy (ptr+len,ptr+len+1);
- }
- ptr[len] = '.';
- ptr[len+1] = '*';
- strcpy (ptr+len+2,ptr+len+3);
- }
-
- /* now use regular expressions */
- sprintf (pattern,"^%s$",s);
- if ((re = regcmp(pattern,(char *) 0)) == NULL)
- printex ("n option regular expression syntax: %s",s);
- for (i=0; i < Actnum; ++i)
- {
- nptr = myfind(Active[i]);
- if (regex(re,nptr->nd_name) != NULL)
- {
- nptr->state |= ormask;
- nptr->state &= andmask;
- }
- }
- regfree (re);
- }
-
- static
- findall (s)
- char *s;
- {
- int len;
- for (len=0; *s != '\0'; ++s,++len)
- {
- if (*s == 'a' && strncmp(s,"all",3) == 0)
- return (len);
- }
- return (-1);
- }
-
- static
- grp_indic (s,ok,serr)
- char *s;
- int ok;
- char *serr; /* only used for NNTP */
- {
- if (ok)
- {
- fgprintf(" %s\n",s);
- return;
- }
- #ifdef NNTP
- if (Machine != NULL)
- {
- fgprintf(" %s, server: %s\n",s,serr);
- return;
- }
- #endif
- fgprintf(" %s - Can't access spool directory\n",s);
- }
-
- /*
- enter newsgroup articles.
- all articles between low and hi are to be included.
-
- Returns the highest number less than an OPENED (not neccesarily
- accepted) article to allow caller to revise "articles read"
- number beyond non-existent articles.
- */
- outgroup (s,low,hi)
- char *s;
- int low,hi;
- {
- int i;
- char subj[RECLEN], lines[RECLEN], auth[RECLEN], gd[RECLEN];
- int ret,op;
-
- ret = low;
- op = 1;
-
- if ((hi-low) > MAXARTRANGE)
- low = hi - MAXARTRANGE;
-
- #ifdef NNTP
- if (Machine != NULL)
- {
- sprintf(gd,"group %s",s);
- if (nntp_put(gd,gd) < 0)
- {
- grp_indic(s,0,gd);
- return (ret);
- }
- }
- else
- {
- g_dir(s,gd);
- if (chdir(gd) < 0)
- {
- grp_indic(s,0);
- return (ret);
- }
- }
- #else
- g_dir(s,gd);
- if (chdir(gd) < 0)
- {
- grp_indic(s,0);
- return (ret);
- }
- #endif /* NNTP */
-
- grp_indic(s,1);
-
- for (i=low+1; i <= hi; ++i)
- {
- if (digname(i,subj,lines,auth,&op) >= 0)
- {
- fw_art(i,subj,lines,auth);
- }
- else
- {
- if (op)
- ret = i;
- }
- }
-
- return(ret);
- }
-
- /*
- ** open article and interpret options, if any. The op parameter is set
- ** to ZERO if and only if an article is opened. Used above as a flag to
- ** indicate no articles opened yet.
- */
- static digname (n, subj, lines, auth, op)
- int n;
- char *subj, *lines, *auth;
- int *op;
- {
- int i,j;
- char t[RECLEN];
- FILE *fp;
- char *(*getfn)();
- char *nfgets();
- char *got;
-
- /* open article */
- #ifdef NNTP
- if (Machine != NULL)
- {
- sprintf (t,"head %d", n);
- if (nntp_put(t,t) < 0)
- return (-1);
- getfn = nntp_get;
- }
- else
- {
- sprintf (t,"%d", n);
- if ((fp = fopen(t,"r")) == NULL)
- return (-1);
- getfn = nfgets;
- }
- #else
- getfn = nfgets;
- sprintf (t,"%d", n);
- if ((fp = fopen(t,"r")) == NULL)
- return (-1);
- #endif
- *op = 0;
-
- /* get subject, from and lines by reading article */
- subj[0] = lines[0] = auth[0] = '?';
- subj[1] = lines[1] = auth[1] = '\0';
-
- for (i = 0; i < HDR_LINES && (got = (*getfn)(t,RECLEN-1,fp)) != NULL; ++i)
- {
- if (index(CHFIRST,t[0]) == NULL)
- continue;
- t[strlen(t) - 1] = '\0';
- if (strncmp(T_head,t,THDLEN) == 0)
- {
- for (j=0; j < Nntopt; ++j)
- {
- if (regex(Negtopt[j],t+THDLEN) != NULL)
- {
- digclose(fp,got);
- return(-1);
- }
- }
- if (Ntopt > 0)
- {
- for (j=0; j < Ntopt; ++j)
- {
- if (regex(Topt[j],t+THDLEN) != NULL)
- break;
- }
- if (j >= Ntopt)
- {
- digclose(fp,got);
- return(-1);
- }
- }
- strcpy(subj,t+THDLEN);
- continue;
- }
- if (strncmp(F_head,t,FHDLEN) == 0)
- {
- for (j=0; j < Nnwopt; ++j)
- {
- if (regex(Negwopt[j],t+FHDLEN) != NULL)
- {
- digclose(fp,got);
- return(-1);
- }
- }
- if (Nwopt > 0)
- {
- for (j=0; j < Nwopt; ++j)
- {
- if (regex(Wopt[j],t+FHDLEN) != NULL)
- break;
- }
- if (j >= Nwopt)
- {
- digclose(fp,got);
- return(-1);
- }
- }
- strcpy(auth,t+FHDLEN);
- continue;
- }
- if (strncmp(L_head,t,LHDLEN) == 0)
- {
- strcpy(lines,t+LHDLEN);
- break;
- }
- }
-
- digclose(fp,got);
-
- /* reject empty or 1 line files */
- if (i < 2)
- return (-1);
-
- return (0);
- }
-
- /*
- ** "close" open article from digname - "got" is not used in non-NNTP case
- */
- digclose(fp,got)
- FILE *fp;
- char *got;
- {
- #ifdef NNTP
- char bufr[RECLEN];
-
- if (Machine == NULL)
- fclose (fp);
- else
- {
- /*
- ** have to finish getting the header lines from the
- ** server
- */
- while (got != NULL)
- got = nntp_get(bufr,RECLEN-1,fp);
- }
- #else
- fclose (fp);
- #endif
- }
-
- /*
- ** special fgets for reading header lines, which unfolds continued lines
- ** and throws away trailing stuff on buffer overflow.
- */
- static char *
- nfgets(buf, size, fp)
- char *buf;
- int size;
- FILE *fp;
- {
- register int c;
-
- while (!feof(fp))
- {
- if ((c = getc(fp)) == '\n')
- {
- if ((c = getc(fp)) == '\t' || c == ' ')
- continue;
- ungetc(c, fp);
- *buf = '\n';
- ++buf;
- *buf = '\0';
- ++buf;
- return (buf);
- }
-
- /* prevent "terminal bombs" */
- if (c < ' ' || c == '\177')
- {
- switch(c)
- {
- case '\r':
- case '\010':
- case '\07':
- break;
- case '\177':
- c = '~';
- break;
- case '\t':
- c = ' ';
- break;
- default:
- if (size > 1)
- {
- *buf = '^';
- ++buf;
- --size;
- }
- c += 'A' - 1;
- break;
- }
- }
-
- if (size > 0)
- {
- *buf = c;
- ++buf;
- --size;
- }
- if (c == '\r')
- {
- if ((c = getc(fp)) != '\n')
- {
- ungetc(c, fp);
- continue;
- }
- if ((c = getc(fp)) != ' ' && c != '\t')
- {
- *buf = '\0';
- ++buf;
- ungetc(c, fp);
- return (buf);
- }
- --buf;
- ++size;
- continue;
- }
- }
-
- *buf = '\0';
- ++buf;
- return (NULL);
- }
-
- static char *Mail[2], *Show[6], *Post[5];
- static char *Priv[8];
- static char *Pool = NULL;
-
- FILE *
- vns_aopen(art,hdr)
- int art;
- ARTHEADER *hdr;
- {
- char buf[RECLEN];
- char *dist, *reply, *from, *ngrp, *flto, *path, *resubj;
- FILE *fp;
- FILE *a_open();
- int n;
- char *mail_trim();
-
- dist = resubj = path = reply = from = ngrp = flto = NULL;
-
- fp = a_open(art);
- if (fp == NULL)
- return(NULL);
-
- /*
- ** we only really need a lot extra if MAILCHOOSE, but allocating
- ** a temporary array of pointers isn't that much. Similarly, a
- ** few assignments, and the "Priv" declaration are only needed
- ** with some define settings. Not worth ifdef'ing.
- */
- Pool = str_tpool(100);
-
- hdr->artid = "<some article>";
- hdr->from = "<somebody>";
- hdr->priv = Priv;
- hdr->postcmd = Poster;
- hdr->mail = Mail;
- hdr->show = Show;
- hdr->post = Post;
- hdr->priv_num = hdr->show_num = hdr->post_num = hdr->mail_num = 0;
-
- /* for conditional is abnormal - expected exit is break */
- for (n=0; n < HDR_LINES && fgets(buf,RECLEN-1,fp) != NULL; ++n)
- {
- /* bail out at first non-header line */
- if (buf[0] == '\n')
- break;
- if (strncmp(buf,RT_head,RTHDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
- reply = str_tstore(Pool,buf+RTHDLEN);
- continue;
- }
- if (strncmp(buf,P_head,PHDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
- path = str_tstore(Pool,buf+PHDLEN);
- continue;
- }
- if (strncmp(buf,DIS_head,DISHDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
- dist = str_tstore(Pool,buf);
- continue;
- }
- if (strncmp(buf,M_head,MHDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
- hdr->artid = str_tstore(Pool,buf+MHDLEN);
- continue;
- }
- if (strncmp(buf,F_head,FHDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
- (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
- from = hdr->from = (hdr->show)[hdr->show_num]+FHDLEN;
- ++(hdr->show_num);
- continue;
- }
- if (strncmp(buf,T_head,THDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
- (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
- if (strncmp(buf+THDLEN,Fpfix,FPFLEN) != 0)
- {
- sprintf(buf,"%s%s%s",T_head,Fpfix,
- ((hdr->show)[hdr->show_num])+THDLEN);
- resubj = str_tstore(Pool,buf);
- }
- else
- resubj = (hdr->show)[hdr->show_num];
- ++(hdr->show_num);
- continue;
- }
- if (strncmp(buf,N_head,NHDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
-
- /* if multiple newsgroups, include in "show" */
- if (index(buf,',') != NULL)
- {
- (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
- ngrp = (hdr->show)[hdr->show_num] + NHDLEN;
- ++(hdr->show_num);
- }
- else
- ngrp = str_tstore(Pool,buf+NHDLEN);
- continue;
- }
- if (strncmp(buf,FT_head,FTHDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
- (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
- flto = (hdr->show)[hdr->show_num] + FTHDLEN;
- ++(hdr->show_num);
- continue;
- }
- if (strncmp(buf,L_head,LHDLEN) == 0)
- {
- buf [strlen(buf)-1] = '\0';
- hdr->lines = atoi(buf+LHDLEN);
- (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
- ++(hdr->show_num);
- continue;
- }
- }
-
- hdr->hlines = n;
-
- #ifdef MAILCHOOSE
- (hdr->priv)[hdr->priv_num] = resubj;
- ++(hdr->priv_num);
- if (reply != NULL)
- {
- (hdr->priv)[hdr->priv_num] = mail_trim(reply);
- ++(hdr->priv_num);
- }
- if (from != NULL)
- {
- (hdr->priv)[hdr->priv_num] = mail_trim(from);
- ++(hdr->priv_num);
- }
- if (path != NULL)
- {
- (hdr->priv)[hdr->priv_num] = mail_trim(path);
- ++(hdr->priv_num);
- }
- #else
- #ifdef MAILSMART
- if (reply == NULL)
- if (from != NULL)
- reply = from;
- else
- {
- if (path != NULL)
- reply = path;
- }
- #else
- if (path != NULL)
- reply = path;
- #endif
- if (reply != NULL)
- reply = mail_trim(reply);
- mail_cmd(hdr,reply,resubj);
- #endif /* MAILCHOOSE */
-
- if (flto == NULL)
- {
- if ((flto = ngrp) == NULL)
- flto = "group.unknown";
- }
- ngrp = rindex(flto,'.');
-
- if (strncmp("mod.",flto,4) == 0 ||
- (ngrp != NULL && strcmp(".announce",ngrp) == 0))
- {
- sprintf(buf,"Cannot post a follow-up to \"%s\", reply with mail to moderator",flto);
- hdr->post_err = str_tstore(Pool,buf);
- return (fp);
- }
-
- if (ngrp != NULL && strcmp(ngrp,".general") == 0)
- {
- *ngrp = '\0';
- sprintf(buf,"%s%s.followup",N_head,flto);
- }
- else
- sprintf(buf,"%s%s",N_head,flto);
- flto = str_tstore(Pool,buf);
-
- hdr->post_err = NULL;
-
- if (resubj != NULL)
- {
- (hdr->post)[hdr->post_num] = resubj;
- ++(hdr->post_num);
- }
-
- #ifdef NNTP
- #ifdef SHOW_FROM
- if (Machine != NULL)
- {
- sprintf(buf,FROM_CR_FORM, F_head, Username, Fmach, Userdesc);
- (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
- ++(hdr->post_num);
- }
- #else
- #ifdef REPLY_CR_FORM
- if (Machine != NULL)
- {
- sprintf(buf,REPLY_CR_FORM, RT_head, Username, Fmach);
- (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
- ++(hdr->post_num);
- }
- #endif
- #endif
- #endif
-
- (hdr->post)[hdr->post_num] = flto;
- ++(hdr->post_num);
-
- sprintf(buf,"%s%s",R_head,hdr->artid);
- (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
- ++(hdr->post_num);
-
- if (dist != NULL)
- {
- (hdr->post)[hdr->post_num] = dist;
- ++(hdr->post_num);
- }
-
- return (fp);
- }
-
- #ifdef MAILCHOOSE
- /*
- ** routine to prompt user for mail path approval
- */
- static
- mail_prompt(hdr)
- ARTHEADER *hdr;
- {
- int i;
- char buf[RECLEN],*ptr;
-
- tty_set(SAVEMODE);
- for (i=1; i < hdr->priv_num; ++i)
- {
- printf("%d - %s\n",i,(hdr->priv)[i]);
- }
- printf("\nType number to choose one of the above, or input address: ");
- fgets(buf,RECLEN-1,stdin);
- tty_set(RESTORE);
-
- ptr = strtok(buf," \t\n");
- if (ptr == NULL)
- ptr = "";
-
- i = strlen(ptr);
- if (i == 1)
- {
- i = atoi(ptr);
- if (i > 0 && i <= hdr->priv_num)
- ptr = (hdr->priv)[i];
- i = 1;
- }
-
- /*
- ** If the user keeps cycling through here on the same article,
- ** we will eventually run out of strings. We made Pool large
- ** enough to make it unlikely (user will have to retry about 80
- ** times without switching articles). Hardly elegant, but should
- ** be sufficient.
- */
- if (i > 1 && hdr->priv_num < 8)
- {
- (hdr->priv)[hdr->priv_num] = str_tstore(Pool,ptr);
- ++(hdr->priv_num);
- }
- mail_cmd(hdr,ptr,(hdr->priv)[0]);
- }
- #endif
-
- /*
- ** trim () off potential mail address, and make copy if needed.
- ** addr must be allocated string.
- */
- static char *
- mail_trim(addr)
- char *addr;
- {
- char buf[RECLEN];
- char *ptr;
-
- if (index(addr,'(') == NULL)
- return(addr);
-
- strcpy(buf,addr);
- ptr = index(buf,'(');
- for (--ptr; *ptr == ' ' || *ptr == '\t'; --ptr)
- ;
- ++ptr;
- *ptr = '\0';
- return (str_tstore(Pool,buf));
- }
-
- /*
- ** format mail command. Subj must point to allocated string.
- */
- static
- mail_cmd(hdr,addr,subj)
- ARTHEADER *hdr;
- char *addr, *subj;
- {
- char buf[RECLEN];
-
- if (addr == NULL || *addr == '\0')
- {
- hdr->mail_err = "No address";
- return;
- }
-
- hdr->mail_err = NULL;
- ;
-
- #ifdef INLETTER
- hdr->mailcmd = Mailer;
- sprintf(buf,"%s%s",TO_head,addr);
- (hdr->mail)[0] = str_tstore(Pool,buf);
- hdr->mail_num = 1;
- #else
- sprintf(buf,Mailer,addr);
- hdr->mailcmd = str_tstore(Pool,buf);
- hdr->mail_num = 0;
- #endif
- if (subj != NULL)
- {
- (hdr->mail)[hdr->mail_num] = subj;
- ++(hdr->mail_num);
- }
- }
-
- static FILE
- *a_open(art)
- int art;
- {
- FILE *fp;
- char buf[RECLEN];
- #ifdef NNTP
- char cmd[RECLEN];
-
- if (Machine == NULL)
- {
- sprintf(buf,"%d",art);
- fp = fopen(buf,"r");
- return (fp);
- }
-
- tmpnam(buf);
- if ((fp = fopen(buf,"w")) == NULL)
- return (NULL);
-
- sprintf(cmd,"head %d",art);
- if (nntp_put(cmd,cmd) < 0)
- {
- fclose(fp);
- unlink(buf);
- return(NULL);
- }
- while (nntp_get(cmd,RECLEN) != NULL)
- fprintf(fp,"%s",cmd);
- fprintf(fp,"\n");
- sprintf(cmd,"body %d",art);
- if (nntp_put(cmd,cmd) >= 0)
- {
- while (nntp_get(cmd,RECLEN) != NULL)
- fprintf(fp,"%s",cmd);
- }
- fclose(fp);
- fp = fopen(buf,"r");
-
- /* "invisible" article - FP opened to unlinked file */
- unlink(buf);
-
- return(fp);
- #else
- sprintf(buf,"%d",art);
- fp = fopen(buf,"r");
- return (fp);
- #endif
- }
-
- vns_aclose(fp)
- FILE *fp;
- {
- if (Pool != NULL)
- str_tfree(Pool);
- Pool = NULL;
- fclose(fp);
- }
-
- /*
- ** we don't use the count / name / mode arguments because this doesn't
- ** implement any fancy article massaging
- */
- vns_asave(art,fp)
- int art;
- FILE *fp;
- {
- char buf[RECLEN];
- FILE *fin;
-
- fin = a_open(art);
-
- while (fgets(buf,RECLEN-1,fin) != NULL)
- fputs(buf,fp);
- fclose(fin);
- }
-
- vns_exit()
- {
- #ifdef NNTP
- if (Fp_trace != NULL)
- {
- fprintf(Fp_trace,"Close Server\n");
- fclose(Fp_trace);
- }
- if (Server_open)
- close_server();
- #endif
- }
-
- #ifdef NNTP
- /*
- ** nntp_get returns char* so it can be used interchangeably with fgets
- ** it appends a newline for the same reason.
- */
- char *
- nntp_get(buf,len)
- char *buf;
- int len;
- {
- if (get_server(buf,len-1) < 0)
- return(NULL);
-
- len = strlen(buf);
- if (len == 0 || (len > 0 && buf[len-1] != '\n'))
- strcpy(buf+len,"\n");
-
- if (Fp_trace != NULL)
- fprintf(Fp_trace,"Got - %s",buf);
-
- if (buf[0] == '.' && buf[1] == '\n')
- return(NULL);
-
- return(buf);
- }
-
- /*
- ** returns failure explanation in estr - estr = str is legal
- */
- nntp_put(str,estr)
- char *str;
- char *estr;
- {
- if (Fp_trace != NULL)
- fprintf(Fp_trace,"Send - %s\n",str);
-
- put_server(str);
- estr[0] = CHAR_INF;
- while (estr[0] == CHAR_INF)
- {
- if (get_server(estr,RECLEN-1) < 0)
- {
- if (Fp_trace != NULL)
- fprintf(Fp_trace,"Ack - no response\n",estr);
- strcpy(estr,"no response");
- return(-1);
- }
-
- if (Fp_trace != NULL)
- fprintf(Fp_trace,"Ack - %s\n",estr);
- }
-
- if (estr[0] != CHAR_OK)
- return (-1);
- return(0);
- }
-
- /*
- ** if not letting the user edit the From line, we have to hack one in
- ** ourselves to prevent getting the thing posted from "news". This
- ** will effectively defeat any that the user may have added, also.
- */
- #ifndef SHOW_FROM
- nntp_post(hdr,fn)
- ARTHEADER *hdr;
- char *fn;
- {
- char tname[80];
- char bufr[RECLEN];
- FILE *fin,*fout;
-
- tmpnam(tname);
-
- if ((fin = fopen(fn,"r")) == NULL || (fout = fopen(tname,"w")) == NULL)
- {
- printf("Can't open article files\n");
- return;
- }
-
- fprintf(fout,FROM_CR_FORM, F_head, Username, Fmach, Userdesc);
- fprintf(fout,"\n");
- while (fgets(bufr,RECLEN-1,fin) != NULL)
- fprintf(fout,"%s",bufr);
- fclose(fin);
- fclose(fout);
-
- sprintf(bufr,hdr->postcmd,tname);
- system(bufr);
- printf("Given to posting program.\n");
- unlink(tname);
- }
- #endif /* SHOW_FROM */
- #endif /* NNTP */
- SHAR_EOF
- fi # end of overwriting check
- # End of shell archive
- exit 0
-
-